package com.library.admin.modules.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.library.admin.modules.role.entity.Role;
import com.library.admin.modules.role.service.RoleService;
import com.library.admin.modules.user.bo.CustomUserDetails;
import com.library.admin.modules.user.bo.UserChangePasswordBO;
import com.library.admin.modules.user.bo.UserForgetPassword;
import com.library.admin.modules.user.bo.UserLoginBO;
import com.library.admin.modules.user.entity.User;
import com.library.admin.modules.user.vo.UserInfoVO;
import com.library.admin.modules.user.vo.UserVO;
import com.library.admin.modules.user.bo.UserPage;
import com.library.admin.modules.user.bo.UserInsert;
import com.library.admin.modules.user.bo.UserUpdate;
import com.library.admin.modules.user.mapper.UserMapper;
import com.library.admin.modules.user.struct.UserStructMapper;
import com.library.admin.modules.user.service.UserService;
import com.library.admin.modules.userrole.bo.UserRoleInsert;
import com.library.admin.modules.userrole.service.UserRoleService;
import com.library.admin.util.JwtTokenUtil;
import com.library.common.enums.ErrorCodeEnum;
import com.library.common.enums.RoleTypeEnum;
import com.library.common.enums.SexEnum;
import com.library.common.enums.StatusEnum;
import com.library.common.exception.BaseException;
import com.library.common.service.bo.CurrentLoginUser;
import com.library.common.util.SmsUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import com.library.common.util.PageCovertUtil;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;


/**
 * @Author xyh
 * @Desc 用户表(User)表服务实现类
 * @Date 2023-09-10 10:51:01
 */

@Log4j2
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserStructMapper userStructMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private RoleService roleService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    /**
     * key: userId
     * value: user
     */
    Map<Integer, User> userMap = new LinkedHashMap<>();

    @Override
    public IPage<UserVO> queryByPage(UserPage page) {
        // 查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(page.getUsername())) {
            queryWrapper.like(User::getUsername, page.getUsername());
        }
        if (page.getPhone() != null) {
            queryWrapper.eq(User::getPhone, page.getPhone());
        }
        // 查询分页数据
        Page<User> userPage = new Page<User>(page.getCurrent(), page.getSize());
        IPage<User> pageData = baseMapper.selectPage(userPage, queryWrapper);
        //转换成vo
        IPage<UserVO> records = PageCovertUtil.pageVoCovert(pageData, UserVO.class);
        if (CollUtil.isNotEmpty(records.getRecords())) {
            records.getRecords().forEach(vo -> {
                vo.setSexName(SexEnum.getValue(vo.getSex()));
                vo.setStatusName(StatusEnum.getValue(vo.getStatus()));
                vo.setRoleNames(getRoleName(vo.getRoleIds()));
            });
        }
        return records;
    }

    private List<String> getRoleName(String roleIds) {
        List<String> roleNames = new ArrayList<>();
        if (StrUtil.isNotEmpty(roleIds)) {
            List<String> list = StrUtil.splitTrim(roleIds, StrUtil.COMMA);
            List<Role> roles = roleService.listByIds(list);
            roles.forEach(r -> {
                roleNames.add(r.getTitle());
            });
        }
        return roleNames;
    }

    @Override
    public void init() {
        List<User> userList = userMapper.selectList(new QueryWrapper<>());
        if (CollUtil.isNotEmpty(userList)) {
            for (User user : userList) {
                userMap.put(user.getId(), user);
            }
            log.info("用户添加缓存完成！");
        }
    }

    @Override
    public UserVO queryById(Integer id) {
        User user = userMap.get(id);
        if (user == null) {
            user = baseMapper.selectById(id);
        }
        UserVO userVO = userStructMapper.userToUserVO(user);
        if (userVO != null) {
            userVO.setSexName(SexEnum.getValue(userVO.getSex()));
            userVO.setStatusName(StatusEnum.getValue(userVO.getStatus()));
        }
        return userVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(UserInsert userInsert) {
        User user = userStructMapper.insertToUser(userInsert);
        //密码进行加密
        String encodePassword = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encodePassword);
        // 用户编号，唯一
        String uuid = System.currentTimeMillis() + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6);
        user.setJobNumber(uuid);
        // 用户姓名,初始值为随机生成
        user.setRealName(RandomUtil.randomString(6));
        user.setAvatar("https://pic.wndbac.cn/file/fea5b7ea8bc13828b71b5.jpg");
        user.setRoleIds(String.valueOf(RoleTypeEnum.ORDINARY.getCode()));
        save(user);
        //维护用户和角色关联信息
        setUserRole(user.getId());
        //加入缓存
        userMap.put(user.getId(), user);
        return true;
    }

    private void setUserRole(Integer userId) {
        List<Integer> list = new ArrayList<>();
        //初始化用户，注册的用户都为普通用户
        list.add(RoleTypeEnum.ORDINARY.getCode());
        UserRoleInsert userRoleInsert = new UserRoleInsert(userId, list);
        userRoleService.insert(userRoleInsert);
    }


    @Override
    public boolean update(UserUpdate userUpdate) {
        User userByPhone = getUserByPhone(userUpdate.getPhone());
        if (userByPhone != null) {
            if (!userByPhone.getUsername().equals(userUpdate.getUsername())){
                return false;
            }
        }
        User user = userStructMapper.updateToUser(userUpdate);
        updateById(user);
        userMap.put(user.getId(), user);
        return true;
    }

    @Override
    public boolean deleteById(Integer id) {
        boolean b = removeById(id);
        if (b) {
            userMap.remove(id);
        }
        return b;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = lambdaQuery().eq(User::getUsername, username).one();
        if (user == null) {
            throw new UsernameNotFoundException(username + "用户名不存！");
        }
        return new CustomUserDetails(user);
    }

    @Override
    public String login(UserLoginBO bo) {
        String token = null;
        try {
            UserDetails userDetails = loadUserByUsername(bo.getUsername());
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(userDetails, null,
                            userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.createJwtToken(userDetails);
            //更新登录的时间
            updateLoginTime(bo.getUsername());
        } catch (AuthenticationException e) {
            log.error("登录失败，异常处理：", e);
        }
        return token;
    }

    private void updateLoginTime(String username) {
        User user = getUserByUsername(username);
        if (user != null) {
            user.setLoginDate(LocalDateTime.now());
            updateById(user);
        } else {
            log.error("更新登录的时间失败！");
        }
    }

    public User getUserByUsername(String username) {
        return lambdaQuery().eq(User::getUsername, username).one();
    }

    @Override
    public UserInfoVO getUserInfo(CurrentLoginUser currentLoginUser) {
        User user = userMap.get(currentLoginUser.getUserId());
        if (user == null) {
            user = this.getById(currentLoginUser.getUserId());
            if (user != null) {
                userMap.put(user.getId(), user);
            } else {
                return new UserInfoVO();
            }
        }
        UserInfoVO vo = userStructMapper.userToUserInfoVO(user);
        return vo;
    }

    public boolean checkCode(String captchaCache, String verifyCode) {
        if (StrUtil.isEmpty(captchaCache) || StrUtil.isEmpty(verifyCode) || !captchaCache.equalsIgnoreCase(verifyCode)) {
            //验证码不正确
            return false;
        }
        return true;
    }

    @Override
    public User getUserByPhone(Long phone) {
        User user = lambdaQuery().eq(User::getPhone, phone).one();
        return user;
    }

    @Override
    public void changePassword(UserChangePasswordBO bo, CurrentLoginUser currentLoginUser) {
        User user = userMap.get(currentLoginUser.getUserId());
        if (user == null || !bCryptPasswordEncoder.matches(bo.getOldPassword(), user.getPassword())) {
            throw new BaseException(ErrorCodeEnum.INCORRECT_OLD_PASSWORD);
        }
        user.setPassword(bCryptPasswordEncoder.encode(bo.getConfirmNewPassword()));
        this.updateById(user);
        userMap.put(user.getId(), user);
    }

    @Override
    public void forgetPassword(User user, UserForgetPassword userForgetPassword) {
        //初始化密码
        String uuid = UUID.randomUUID().toString().substring(0, 6);
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(uuid);
        //发送短信
        try {
            SmsUtil.sendSms(String.valueOf(userForgetPassword.getPhone()), uuid);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        user.setPassword(encode);
        this.updateById(user);
        userMap.put(user.getId(), user);
        log.info("重置密码成功：账号：{}，手机号：{}", userForgetPassword.getUsername(), userForgetPassword.getPhone());
    }


    /**
     * 充值
     *
     * @param userUpdate
     */
    @Override
    public void setInvestMoney(UserUpdate userUpdate) {
        User user = userMap.get(userUpdate.getId());
        BigDecimal decimal = user.getBalance().add(userUpdate.getBalance());
        user.setBalance(decimal);
        updateById(user);
        userMap.put(user.getId(), user);
    }

}
